home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 03 - Advanced Graphics / Example 4 - Encoder / encoder.c < prev    next >
Text File  |  1995-03-10  |  10KB  |  361 lines

  1. //
  2. //    File: encoder.c
  3. //
  4. //    This file contains the routines to encode picts as shapes.
  5. //
  6. //    2/19/95 -- Created by Mick
  7. //
  8.  
  9. // include files
  10.  
  11. #include "global.h"
  12.  
  13. #include <QDOffscreen.h>
  14.  
  15. #include <stdio.h>
  16.  
  17. #include "encoder.h"
  18.  
  19. #include "main.h"
  20.  
  21. // defines for this file
  22.  
  23. #define kEndShapeToken                    0L                // the end of shape maker
  24. #define kLineStartToken                    1L                // the line start marker
  25. #define kDrawPixelsToken            2L                // the draw run marker
  26. #define kSkipPixelsToken                3L                // the skip pixels marker
  27.  
  28. #define kClearColorIndex                0                // the index of the color defined as clear (in this case, white)
  29.  
  30. // typedefs for this file
  31.  
  32. // global function declarations
  33.  
  34. void startupEncoder( void );
  35. void shutdownEncoder( void );
  36. void doEncode( void );
  37.  
  38. // global data owned by this file
  39.  
  40. GWorldPtr gOffscreenBuffer;                                    // the port and gdevice of the offscreen buffer
  41. PixMapHandle gOffscreenPixels;                                // the actual pixmap of the offscreen buffer
  42. Rect gOffscreenRect = { 0, 0, 480, 640 };                    // the size of the offscreen buffer
  43.  
  44. // local function declarations
  45.  
  46. static Handle encodeRect( Rect *inRect );
  47.  
  48. // static data
  49.  
  50. // functions
  51.  
  52. //
  53. //    startupEncoder -
  54. //
  55. //    Create the buffer for the the encode routine.
  56. //
  57.  
  58. void startupEncoder( void )
  59. {
  60.     printf( "Allocating offscreen\n" );
  61.  
  62.     // create the offscreen gworld
  63.     NewGWorld( &gOffscreenBuffer, 8, &gOffscreenRect, gAppColorTable, ( GDHandle )kNil, keepLocal );
  64.  
  65.     // get the pixel map and rect
  66.     gOffscreenPixels = GetGWorldPixMap( gOffscreenBuffer );
  67. }
  68.  
  69.  
  70. //
  71. //    shutdownEncoder -
  72. //
  73. //    Release all the memory used by the encoder.
  74. //
  75.  
  76. void shutdownEncoder( void )
  77. {
  78.     printf( "Disposing offscreen\n" );
  79.  
  80.     // dump the offscreen gworld
  81.     DisposeGWorld( gOffscreenBuffer );
  82. }
  83.  
  84.  
  85. //
  86. //    doEncode -
  87. //
  88. //    Encode all the PICTs from the resource fork.
  89. //
  90.  
  91. void doEncode( void )
  92. {
  93.     CGrafPtr oldPort;                                                        // the port in place when we started
  94.     GDHandle oldGDevice;                                            // the gdevice in place when we started
  95.     unsigned short numResources;            // the number of a type or resource ( used for both PICTs and Sprts )
  96.     unsigned short resCounter;                    // a counter to scan resources
  97.     Handle spriteResource;                                        // a handle to a sprite resource
  98.     PicHandle pictResource;                                    // a handle to a pict resource
  99.     signed short resID;                                            // the id of the resource that we are examining
  100.     ResType resType;                                                        // the type of resource that we are examining ( needed for GetResInfo )
  101.     Str255 resName;                                                        // the name of the resource that we are examining
  102.     
  103.     // save the current port and device
  104.     GetGWorld( &oldPort, &oldGDevice );
  105.     
  106.     // set the offscreen
  107.     LockPixels( gOffscreenPixels );
  108.     SetGWorld( gOffscreenBuffer, ( GDHandle )kNil );
  109.     
  110.     // remove all the sprite resources
  111.     printf( "Removing old sprites - " );
  112.     
  113.     // determine the number of sprite resources
  114.     numResources = Count1Resources( kSpriteResType );
  115.     
  116.     // if there are any,
  117.     if ( numResources != 0 )
  118.         {
  119.             // get each one,
  120.             for( resCounter = 1; resCounter <= numResources; resCounter++ )
  121.                 {
  122.                     // and delete it
  123.                     spriteResource = Get1IndResource( kSpriteResType, resCounter );
  124.                     RmveResource( spriteResource );
  125.                     DisposeHandle( spriteResource );
  126.                 }
  127.         }
  128.  
  129.     // let the user know
  130.     printf( "Done\n" );
  131.  
  132.     // determine the number of PICT resources
  133.     numResources = Count1Resources( 'PICT' );
  134.     
  135.     // if there are not any,
  136.     if ( numResources == 0 )
  137.         {
  138.             // tell the user
  139.             printf( "There are no picts to encode!\n" );
  140.         }
  141.     else
  142.         {
  143.             // get each one,
  144.             for( resCounter = 1; resCounter <= numResources; resCounter++ )
  145.                 {
  146.                     // load the pict
  147.                     pictResource = ( PicHandle )Get1IndResource( 'PICT', resCounter );
  148.                     HLock( ( Handle )pictResource );
  149.  
  150.                     // determine its id and name
  151.                     GetResInfo( ( Handle )pictResource, &resID, &resType, resName );
  152.  
  153.                     // let the user know what is going on
  154.                     printf( "\tProcessing PICT #%d - ", resID );
  155.  
  156.                     // erase the background
  157.                     EraseRect( &( ( *pictResource )->picFrame ) );
  158.                     
  159.                     // draw the picture
  160.                     DrawPicture( pictResource, &( ( *pictResource )->picFrame ) );
  161.  
  162.                     // encode the data
  163.                     spriteResource = encodeRect( &( ( *pictResource )->picFrame ) );
  164.  
  165.                     // add the new resource to the file
  166.                     AddResource( spriteResource, kSpriteResType, resID, resName );
  167.                     WriteResource( spriteResource );
  168.                     ReleaseResource( spriteResource );
  169.  
  170.                     // release the pict
  171.                     ReleaseResource( ( Handle )pictResource );
  172.                     
  173.                     // let the user know
  174.                     printf( "Done\n" );
  175.                 }
  176.         }
  177.     
  178.     // restore the previous port and device
  179.     SetGWorld( oldPort, oldGDevice );
  180.     
  181.     // unlock the pixels
  182.     UnlockPixels( gOffscreenPixels );
  183. }
  184.  
  185.  
  186. //
  187. //    encodeRect -
  188. //
  189. //    Encode the data in the given rect into a sprite.
  190. //
  191.  
  192. Handle encodeRect( Rect *inRect )
  193. {
  194.     Handle shapeHandle;                                                // the shape that we create in the function
  195.     unsigned short shapeHeight;                // the height of the shape
  196.     unsigned short shapeWidth;                    // the width of the shape
  197.     unsigned char *destPtr;                            // the current position in the shape
  198.     unsigned char *srcPtr;                                // the current position in the souce graphic data
  199.     unsigned char *baseAddr;                        // the base address of the source pixmap
  200.     unsigned long rowBytes;                            // the row bytes of the source pixmap
  201.     unsigned char *rowStart;                        // the start of the current row in the pixmap
  202.     unsigned long yCounter;                                // a counter to scan the shape vertically
  203.     unsigned long xCounter;                                // a counter to scan the shape horizontally
  204.     unsigned char drawRunFlag;                    // are we in a draw pixels run?
  205.     unsigned char skipRunFlag;                    // are we in a skip pixels run?
  206.     unsigned char *lineStartPtr;                // where is the line start token for this line
  207.     unsigned char *runTokenPtr;                // where is the token for the current run
  208.     unsigned long runCounter;                        // how long is the current run? 
  209.     
  210.     // determine the width and height of the shape (we use these values a lot)
  211.     shapeHeight = inRect->bottom - inRect->top;
  212.     shapeWidth = inRect->right - inRect->left;
  213.     
  214.     // create a handle big enough for the worst case encoding
  215.     // ( 8 bytes/pixel + 4 bytes/row + 4 bytes/shape (end token) + 8 bytes/shape (rect) )
  216.     shapeHandle = NewHandle( 8 * shapeHeight * shapeWidth + 4 * shapeHeight + 4 + 8 );
  217.     
  218.     // make sure that we got the buffer
  219.     if( shapeHandle == ( Handle )kNil )
  220.         {
  221.             printf( "Error - Could not allocate buffer to build shape\n");
  222.             return shapeHandle;
  223.         }
  224.     
  225.     // lock the handle and get the pointer
  226.     HLock( shapeHandle );
  227.     destPtr = ( unsigned char * )( *shapeHandle );
  228.     
  229.     // store the shape rect
  230.     *( ( Rect * )destPtr ) = *inRect;
  231.     destPtr += sizeof( Rect );
  232.     
  233.     // get the location of the source data
  234.     baseAddr = ( unsigned char * )GetPixBaseAddr( gOffscreenPixels );
  235.     rowBytes = ( *gOffscreenPixels )->rowBytes & 0x3fff;
  236.     rowStart = baseAddr + rowBytes * inRect->top + inRect->left;
  237.     
  238.     // scan the shape row by row
  239.     for( yCounter = 0; yCounter < shapeHeight; yCounter++ )
  240.         {
  241.             // store the location of this line start
  242.             lineStartPtr = destPtr;
  243.             destPtr += sizeof( unsigned long );
  244.             
  245.             // at the beginning of each row we are not in any run
  246.             drawRunFlag = kFalse;
  247.             skipRunFlag = kFalse;
  248.             
  249.             // move to the start of the row
  250.             srcPtr = rowStart;
  251.             
  252.             // scan each row of the shape
  253.             for( xCounter = 0; xCounter < shapeWidth; xCounter++ )
  254.                 {
  255.                     // is this pixel clear?
  256.                     if ( *srcPtr == kClearColorIndex )
  257.                         {
  258.                             // are we in a draw run?
  259.                             if ( drawRunFlag )
  260.                                 {
  261.                                     // end the draw run
  262.                                     drawRunFlag = kFalse;
  263.                                     
  264.                                     // create the draw token
  265.                                     *( ( unsigned long * )runTokenPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
  266.                                     
  267.                                     // pad to a mulitple of four
  268.                                     *( ( unsigned long * )destPtr ) = 0L;
  269.                                     destPtr += ( ( runCounter & 3L ) == 0 ) ? 0 : ( 4 - ( runCounter & 3L ) );
  270.                                 }
  271.                             
  272.                             // are we in a skip run
  273.                             if ( skipRunFlag )
  274.                                 {
  275.                                     // continue it
  276.                                     runCounter++;
  277.                                 }
  278.                             else
  279.                                 {
  280.                                     // start one
  281.                                     skipRunFlag = kTrue;
  282.                                     runCounter = 1;
  283.                                 }
  284.                         }
  285.                     else
  286.                         {
  287.                             // are we in a skip run
  288.                             if ( skipRunFlag )
  289.                                 {
  290.                                     // end the skip run
  291.                                     skipRunFlag = kFalse;
  292.                                     
  293.                                     // create the skip token
  294.                                     *( ( unsigned long * )destPtr ) = ( kSkipPixelsToken << 24 ) + runCounter;
  295.                                     destPtr += sizeof( unsigned long );
  296.                                 }
  297.                             
  298.                             // are we in a draw run
  299.                             if ( drawRunFlag )
  300.                                 {
  301.                                     // continue it
  302.                                     runCounter++;
  303.                                     
  304.                                     // copy the pixel
  305.                                     *destPtr = *srcPtr;
  306.                                     destPtr++;
  307.                                 }
  308.                             else
  309.                                 {
  310.                                     // start one
  311.                                     drawRunFlag = kTrue;
  312.                                     runCounter = 1;
  313.                                     
  314.                                     // save the location of the token (so we can fill it in later)
  315.                                     runTokenPtr = destPtr;
  316.                                     destPtr += sizeof( unsigned long );
  317.                                     
  318.                                     // copy the pixel
  319.                                     *destPtr = *srcPtr;
  320.                                     destPtr++;
  321.                                 }
  322.                         }
  323.                     
  324.                     // move to the next byte
  325.                     srcPtr++;
  326.                 }
  327.             
  328.             // are we in a draw run
  329.             if( drawRunFlag )
  330.                 {
  331.                     // end the draw run
  332.                     drawRunFlag = kFalse;
  333.                     
  334.                     // create the draw token
  335.                     *( ( unsigned long * )runTokenPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
  336.                     
  337.                     // pad to a mulitple of four
  338.                     *( ( unsigned long * )destPtr ) = 0L;
  339.                     destPtr += ( ( runCounter & 3L ) == 0 ) ? 0 : ( 4 - ( runCounter & 3L ) );
  340.                 }
  341.             
  342.             // create the line start token
  343.             *( ( unsigned long * )lineStartPtr ) = ( kLineStartToken << 24 ) + ( destPtr - ( lineStartPtr + 4 ) );
  344.             
  345.             // move the row start to the next row
  346.             rowStart += rowBytes;
  347.         }
  348.     
  349.     // create the end of shape token
  350.     *( ( unsigned long * )destPtr ) = kEndShapeToken << 24;
  351.     destPtr += sizeof( unsigned long );
  352.     
  353.     // Unlock the handle
  354.     HUnlock( shapeHandle );
  355.     
  356.     // Resize the handle to match the real size of the shape
  357.     SetHandleSize( shapeHandle, destPtr - ( unsigned char * )( *shapeHandle ) );
  358.     
  359.     // return the handle
  360.     return shapeHandle;
  361. }